using System;
using System.Collections.Generic;
using System.Text;
using Weazel.Math;

namespace Weazel.Gezel.Simulator.Reference.IpBlocks
{
    [IpBlockAttribute("opbslave")]
    public class OpbSlave : AbstractIpBlock
    {
        private uint lowAddress;
        public uint LowAddress
        {
            get { return lowAddress; }
            set { lowAddress = value; }
        }

        private uint highAddress;
        public uint HighAddress
        {
            get { return highAddress; }
            set { highAddress = value; }
        }

        private const string slaveXferAck = "s_xfer_ack";
        private const string slaveDataBus = "s_dbus";

        private const string opbSelect = "opb_select";
        private const string opbReadNotWrite = "opb_rnw";
        private const string opbAddressBus = "opb_abus";
        private const string opbDataBus = "opb_dbus";

        private int slaveXferAckIndex = -1;
        private int slaveDataBusIndex = -1;

        private int opbSelectIndex = -1;
        private int opbReadNotWriteIndex = -1;
        private int opbAddressBusIndex = -1;
        private int opbDataBusIndex = -1;

        #region Properties

        public bool SlaveXferAck
        {
            get { return ioValues[slaveXferAckIndex].ToUInt() == 1; }
            set
            {
                if (value == true)
                    ioValues[slaveXferAckIndex].Assign(1);
                else
                    ioValues[slaveXferAckIndex].Assign(0);
            }
        }

        public uint SlaveDataBus
        {
            get { return ioValues[slaveDataBusIndex].ToUInt(); }
            set { ioValues[slaveDataBusIndex].Assign(value); }
        }

        public bool OpbSelect
        {
            get { return ioValues[opbSelectIndex].ToUInt() == 1; }
            set
            {
                if (value == true)
                    ioValues[opbSelectIndex].Assign(1);
                else
                    ioValues[opbSelectIndex].Assign(0);
            }
        }

        public bool OpbReadNotWrite
        {
            get { return ioValues[opbReadNotWriteIndex].ToUInt() == 1; }
            set
            {
                if (value == true)
                    ioValues[opbReadNotWriteIndex].Assign(1);
                else
                    ioValues[opbReadNotWriteIndex].Assign(0);
            }
        }

        public uint OpbAddressBus
        {
            get { return ioValues[opbAddressBusIndex].ToUInt(); }
            set { ioValues[opbAddressBusIndex].Assign(value); }
        }

        public uint OpbDataBus
        {
            get { return ioValues[opbDataBusIndex].ToUInt(); }
            set { ioValues[opbDataBusIndex].Assign(value); }
        }

        #endregion

        public OpbSlave(string name)
            : base(name)
        {
        }

        public override void SetParameter(string name)
        {
            string field = name.Substring(0, name.IndexOf('='));
            string value = name.Substring(name.IndexOf('=') + 1);

            // no parameters ..

            if (field.Trim() == "low_address")
                lowAddress = Convert.ToUInt32(value.Trim(), 16);
            else if (field.Trim() == "high_address")
                highAddress = Convert.ToUInt32(value.Trim(), 16);
        }

        public override bool CheckTerminal(int n, string tname, IoDirection dir)
        {
            if (tname == slaveXferAck && dir == IoDirection.Input)
                slaveXferAckIndex = n;
            else if (tname == slaveDataBus && dir == IoDirection.Input)
                slaveDataBusIndex = n;

            else if (tname == opbSelect && dir == IoDirection.Output)
                opbSelectIndex = n;
            else if (tname == opbReadNotWrite && dir == IoDirection.Output)
                opbReadNotWriteIndex = n;
            else if (tname == opbAddressBus && dir == IoDirection.Output)
                opbAddressBusIndex = n;
            else if (tname == opbDataBus && dir == IoDirection.Output)
                opbDataBusIndex = n;

            return true;
        }



        public override void Evaluate(long g, bool topLevelCall)
        {            
            if (topLevelCall)
            {
                // update all in signals (direction out from IP)
                foreach (InputSignal i in Inputs)
                {                    
                    ioValues[(int)ioMap[i]] = i.Evaluate(this, g);
                }

            }

            if (generation != g)
            {
                // this is run (at most) once per cycle

                Run();
                generation = g;
            }
        }

        public override void Run()
        {

        }
    }
}
